package cc.wanforme.st.server.base.service.impl;

import cc.wanforme.st.server.base.entity.Role;
import cc.wanforme.st.server.base.entity.User;
import cc.wanforme.st.server.base.entity.UserRole;
import cc.wanforme.st.server.base.mapper.RoleMapper;
import cc.wanforme.st.server.base.mapper.UserMapper;
import cc.wanforme.st.server.base.mapper.UserRoleMapper;
import cc.wanforme.st.server.base.service.IUserRoleService;
import cc.wanforme.st.server.util.AssertCheck;
import cc.wanforme.st.server.vo.base.UserRoleVo;
import cc.wanforme.st.server.vo.base.UserVo;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author wanne
 * @since 2023-01-03
 */
@Service
public class UserRoleServiceImpl extends ServiceImpl<UserRoleMapper, UserRole>
	implements IUserRoleService {

	@Autowired
	private UserMapper userMapper;
	@Autowired
	private RoleMapper roleMapper;
	
	@Override
	public List<UserRole> selectRoles(long userId) {
		return this.baseMapper.selectRoles(userId);
	}

	/**获取用户的所有角色
	 * @param userId
	 * @return
	 */
	@Override
	public UserRoleVo selectUserAndRoles(long userId){
		User user= userMapper.selectById(userId);
		AssertCheck.nonNull(user, "用户不存在");
		
		List<UserRole> list = this.baseMapper.selectRoles(userId);
		if(list==null || list.isEmpty()) {
			return new UserRoleVo();
		}
		
		List<Role> roles = new ArrayList<>(list.size());
		for (UserRole ur : list) {
			Role role = roleMapper.selectByRoleCode(ur.getRole());
			if(role!=null) {
				roles.add(role);
			}
		}
		
		UserRoleVo re = new UserRoleVo(user, roles);
		return re;
	}

	@Override
	public UserRole saveVo(UserRole vo) {
		AssertCheck.nonNull(vo.getId(), "未知权限");
		AssertCheck.nonNull(vo.getUserId(), "未知用户");
		AssertCheck.nonNull(vo.getRole(), "未知角色");
		
		User user = userMapper.selectById(vo.getUserId());
		AssertCheck.nonNull(user, "角色不存在");
		
		Role role = roleMapper.selectById(vo.getRole());
		AssertCheck.nonNull(role, "角色不存在");
		
		this.save(vo);
		return vo;
	}

	@Override
	public void updateVo(UserRole vo) {
		AssertCheck.nonNull(vo.getId(), "未知权限");
		AssertCheck.nonNull(vo.getUserId(), "未知用户");
		AssertCheck.nonNull(vo.getRole(), "未知角色");
		
		User user = userMapper.selectById(vo.getUserId());
		AssertCheck.nonNull(user, "角色不存在");
		
		Role role = roleMapper.selectById(vo.getRole());
		AssertCheck.nonNull(role, "角色不存在");
		
		this.updateById(vo);
	}

	@Override
	public void deleteVo(String id) {
		this.baseMapper.deleteById(id);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateUserRoles(UserRoleVo vo) {
		Optional<Long> userIdOpt = Optional.ofNullable(vo)
				.map(UserRoleVo::getUser)
				.map(UserVo::getId);
		AssertCheck.check(userIdOpt, "未知用户");
		
		Optional<List<Role>> rolesOpt = Optional.ofNullable(vo)
				.map(UserRoleVo::getRoles);
		AssertCheck.check(rolesOpt, "缺少权限");
		
		Long userId = userIdOpt.get();
		List<String> newRolelist = rolesOpt.get().stream()
					.map(Role::getRoleCode)
					.collect(Collectors.toList());
		
		List<UserRole> oldAll = this.baseMapper.selectRoles(userId);
		// 删除
		List<UserRole> delList = oldAll.stream()
				.filter(e -> !newRolelist.contains(e.getRole()))
				.collect(Collectors.toList());
		
		// 旧所有
		List<String> oldAllCode = oldAll.stream()
				.map(UserRole::getRole)
				.collect(Collectors.toList());
		
		// 新增
		List<UserRole> saveList = newRolelist.stream()
				.filter(e -> !oldAllCode.contains(e))
				.map(e -> {
					UserRole ur = new UserRole();
					ur.setUserId(userId);
					ur.setRole(e);
					return ur;
				}).collect(Collectors.toList());
		
		for (UserRole del : delList) {
			this.baseMapper.deleteById(del.getId());
		}
		this.saveBatch(saveList, 100);
		
		SecurityContextHolder.clearContext(); // 清除 spring 会话缓存
	}
	
}
